package pr3.cromosoma;

import java.util.List;
import pr3.funcion.DU;

import pr3.funcion.Funcion;
import pr3.funcion.NOP;

public class CromosomaArbol extends Cromosoma<CromosomaArbol> implements Iterable<Funcion> {

    private final NOP raiz;
    private static List<Estado> estados = Utilidades.carga();

    private CromosomaArbol() {
        raiz = new NOP();
    }

    public CromosomaArbol(int profundidad, int profMin) {
        raiz = new NOP() {

            @Override
            public int getProfundidad() {
                //asi la nodos hijos sera la real
                return -1;
            }
            
        };
        raiz.setArgumento(Utilidades.generarArbol(profundidad, profMin));
        raiz.getArgumento().setPadre(raiz);
        for(Funcion f : this) {
            if(f != raiz) {
                assert(f.getPadre() != null);
            }
        }
        assert(getProfundidad() <= profundidad);
    }

    @Override
    public String toString() {
        return "( "+getProfundidad()+" ) -> \n"+raiz.getArgumento().toString();
    }

    @Override
    public double evalua() {
        int aptitud = 0;
        Estado copia = new Estado();
        for (Estado e : estados) {
            DU.nuevoCaso();
            copia.copiar(e);
            raiz.evaluar(copia);
            if (copia.isCorrecto()) {
                aptitud++;
            }
        }
        return aptitud;
    }

    @Override
    public void copia(CromosomaArbol otro) {
        raiz.setArgumento(((CromosomaArbol) otro).raiz.getArgumento().clone());
        raiz.getArgumento().setPadre(raiz);
        setPuntuacion(otro.getPuntuacion());
        setAdaptacion(otro.getAdaptacion());
    }

    @Override
    public CromosomaArbol clone() {
        CromosomaArbol clon = new CromosomaArbol();
        clon.copia(this);
        return clon;
    }

    public Funcion getRaiz() {
        return raiz;
    }

    /**
     * @return devuelve un iterador que recorre el arbol en profundidad
     */
    @Override
    public CromosomaIterator iterator() {
        return new CromosomaIterator(this);
    }
    
    public int getNumNodos() {
        int numNodos = 0;
        for (Funcion f : this) {
            numNodos++;
        }
        return numNodos - 1;
    }
    
    public int getNumNodos(int maxProf) {
        CromosomaIterator it = new CromosomaIterator(this, maxProf);
        int numNodos = 0;
        while(it.hasNext()) {
            it.next();
            numNodos++;
        }
        return numNodos - 1;
    }
    
    public int getProfundidad() {
        int prof = Integer.MIN_VALUE;
        for (Funcion f : this) {
            int profActual = f.getProfundidad();
            if(profActual > prof) {
                prof = profActual;
            }
        }
        return prof;
    }
}
